package com.iflytek.jzcpx.procuracy.web.card.controller;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Map;

import cn.hutool.core.io.IoUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.iflytek.jzcpx.procuracy.card.common.FileUtils;
import com.iflytek.jzcpx.procuracy.card.config.ElleServerProps;
import com.iflytek.jzcpx.procuracy.common.enums.CommonResultEnum;
import com.iflytek.jzcpx.procuracy.common.exception.InvalidParameterException;
import com.iflytek.jzcpx.procuracy.common.exception.ViewException;
import com.iflytek.jzcpx.procuracy.common.result.WebResult;
import com.iflytek.jzcpx.procuracy.common.util.JSONUtil;
import com.iflytek.jzcpx.procuracy.ocr.entity.swx.result.Wjsbjg;
import com.iflytek.jzcpx.procuracy.ocr.recognize.model.OcrResultRequestVo;
import com.iflytek.jzcpx.procuracy.ocr.service.OcrService;
import com.iflytek.jzcpx.procuracy.tools.elle.ElleTextTypeEnum;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
 * @date 2019/9/25 14:29
 */
@RestController
@RequestMapping("/test")
public class TestController {
    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    private ElleServerProps elleProps;

    @Autowired
    private OcrService ocrService;

    @PostMapping("/empty")
    @ApiOperation(value = "空接口", notes = "空接口")
    public WebResult<Wjsbjg> empty(@RequestBody String req) {
        logger.info("空接口, size: {}", StringUtils.length(req));
        WebResult<Wjsbjg> result = WebResult.success(null);
        result.setCode(200);
        result.setSuccess(true);
        return result;
    }

    @PostMapping("/noresp")
    @ApiOperation(value = "有处理无响应", notes = "有处理无响应")
    public WebResult<Wjsbjg> noresp(@RequestBody OcrResultRequestVo ocrParam, HttpServletRequest request) {
        String wjbh = ocrParam.getWjbh();
        logger.info("获取文件OCR识别结果, wjbh: {}", wjbh);

        WebResult<Wjsbjg> result = WebResult.success(null);
        result.setCode(200);
        result.setSuccess(true);
        try {
            Wjsbjg wjsbjg = ocrService.recognize(ocrParam);
            result.setData(wjsbjg);
            String respJson = JSONUtil.toStrDefault(result);
            logger.info("获取文件OCR识别结果完成, wjbh: {}, respLength: {}", wjbh, StringUtils.length(respJson));

            result.setData(null);
        }
        catch (Exception e) {
            logger.warn("获取文件OCR识别结果异常, wjbh: {}", wjbh, e);
        }
        return result;
    }

    @PostMapping("/normal")
    @ApiOperation(value = "有处理有响应", notes = "有处理有响应")
    public WebResult<Wjsbjg> normal(@RequestBody OcrResultRequestVo ocrParam, HttpServletRequest request) {
        String wjbh = ocrParam.getWjbh();
        logger.info("获取文件OCR识别结果, wjbh: {}", wjbh);

        try {
            Wjsbjg wjsbjg = ocrService.recognize(ocrParam);
            logger.info("获取文件OCR识别结果完成, wjbh: {}", wjbh);

            WebResult<Wjsbjg> result = WebResult.success(wjsbjg);
            result.setCode(200);
            result.setSuccess(true);
            return result;
        }
        catch (Exception e) {
            logger.warn("获取文件OCR识别结果异常, wjbh: {}", wjbh, e);
            return buildExceptionResult(e);
        }
    }

    @PostMapping("/normal_2")
    @ApiOperation(value = "有处理有响应", notes = "有处理有响应")
    public WebResult<Wjsbjg> normal_2(@RequestBody String reqBody, HttpServletRequest request) {
        logger.info("获取文件OCR识别结果, 收到请求");
        OcrResultRequestVo ocrParam = JSONObject.parseObject(reqBody, OcrResultRequestVo.class);
        String wjbh = ocrParam.getWjbh();
        logger.info("获取文件OCR识别结果, wjbh: {}", wjbh);

        try {
            Wjsbjg wjsbjg = ocrService.recognize(ocrParam);
            logger.info("获取文件OCR识别结果完成, wjbh: {}", wjbh);

            WebResult<Wjsbjg> result = WebResult.success(wjsbjg);
            result.setCode(200);
            result.setSuccess(true);
            return result;
        }
        catch (Exception e) {
            logger.warn("获取文件OCR识别结果异常, wjbh: {}", wjbh, e);
            return buildExceptionResult(e);
        }
    }

    @PostMapping(value = "/normal_3", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "有处理有响应", notes = "有处理有响应")
    public WebResult<Wjsbjg> normal_3(HttpServletRequest request) {
        logger.info("获取文件OCR识别结果, 收到请求");
        String body = null;
        try (ServletInputStream inputStream = request.getInputStream()) {
            body = IoUtil.read(inputStream, StandardCharsets.UTF_8);
            logger.info("获取文件OCR识别结果, 请求体读取完成}");
        }
        catch (Exception e) {
            logger.warn("获取文件OCR识别结果异常, 请求体内容读取失败", e);
            return buildExceptionResult(e);
        }

        OcrResultRequestVo ocrParam = JSONObject.parseObject(body, OcrResultRequestVo.class);
        String wjbh = ocrParam.getWjbh();
        logger.info("获取文件OCR识别结果, wjbh: {}", wjbh);

        try {
            Wjsbjg wjsbjg = ocrService.recognize(ocrParam);
            logger.info("获取文件OCR识别结果完成, wjbh: {}", wjbh);

            WebResult<Wjsbjg> result = WebResult.success(wjsbjg);
            result.setCode(200);
            result.setSuccess(true);
            return result;
        }
        catch (Exception e) {
            logger.warn("获取文件OCR识别结果异常, wjbh: {}", wjbh, e);
            return buildExceptionResult(e);
        }
    }

    private WebResult<Wjsbjg> buildExceptionResult(Exception e) {
        if (e instanceof InvalidParameterException) {
            return new WebResult<>(((InvalidParameterException) e).getResultType());
        }
        else if (e instanceof ViewException) {
            return new WebResult<>(((ViewException) e).getResultType());
        }

        WebResult<Wjsbjg> result = new WebResult<>();
        result.update(CommonResultEnum.FAILED, e.getMessage());
        return result;
    }

    @PostMapping(value = "/elle/word", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String elleTest(@RequestParam MultipartFile file, @RequestParam(required = false) ElleTextTypeEnum type) {
        logger.info("elle 测试, type: {}, file: {}", type, file.getOriginalFilename());

        // 根据文件名解析文件类型
        String textType = parseType(file.getOriginalFilename(), type);
        if (StringUtils.isBlank(textType)) {
            logger.warn("文书类型无法确定");
            return null;
        }

        String content = extractWordText(file);
        System.out.println(content);

        String body = buildBody(textType, content);

        String resp = requestElle(body);
        System.out.println(JSONObject.parseObject(resp).getString("tag"));

        logger.info("request:  {}", body);
        logger.info("response:  {}", resp);
        return simplify(resp);
    }

    private String requestElle(String body) {
        String url = StringUtils.removeEnd(elleProps.getServer(), "/") +
                StringUtils.prependIfMissing(elleProps.getPath(), "/");
        return HttpRequest.post(url).body(body).header("Content-Type", "application/json; charset=UTF-8")
                          .timeout(10000).execute().body();
    }

    private String buildBody(@RequestParam(required = false) String type, String content) {
        JSONObject params = new JSONObject();
        params.put("protocol_level", "2");
        params.put("usrId", "aktq");
        params.put("trackId", String.valueOf(System.currentTimeMillis()));
        params.put("rlt_switch", true);
        JSONArray texts = new JSONArray();
        params.put("texts", texts);

        JSONObject text = new JSONObject();
        texts.add(text);
        text.put("type", type);
        text.put("content", StringUtils.abbreviate(StringUtils.stripStart(content, null), 80));
        System.out.println(params.toJSONString());
        text.put("content", content);

        System.out.println();
        return params.toJSONString();
    }

    private String parseType(String filename, ElleTextTypeEnum originalType) {
        if (originalType != null) {
            return originalType.name();
        }

        if (filename.contains("起诉意见书")) {
            return ElleTextTypeEnum.qsyjs.name();
        }

        if (filename.contains("提请批准逮捕书")) {
            return ElleTextTypeEnum.tqpzdbs.name();
        }

        if (filename.contains("判决书")) {
            return ElleTextTypeEnum.pjs.name();
        }

        if (filename.contains("不批准逮捕决定书")) {
            return ElleTextTypeEnum.bpzdbjds.name();
        }

        if (filename.contains("批准逮捕决定书")) {
            return ElleTextTypeEnum.pzdbjds.name();
        }

        if (filename.contains("不起诉决定书")) {
            return ElleTextTypeEnum.bqsjds.name();
        }

        if (filename.contains("起诉书")) {
            return ElleTextTypeEnum.qss.name();
        }

        return null;
    }

    private String simplify(String resp) {
        if (StringUtils.isBlank(resp)) {
            return resp;
        }

        JSONObject respJson = JSONObject.parseObject(resp);
        if (!respJson.getJSONObject("state").getBooleanValue("success")) {
            return resp;
        }

        JSONObject result = new JSONObject();

        JSONObject tagJson = JSONObject.parseObject(respJson.getString("tag"));
        JSONArray extractInfoVec = tagJson.getJSONArray("extractInfoVec");
        if (extractInfoVec.isEmpty()) {
            return resp;
        }
        JSONObject extractInfo = ((JSONObject) extractInfoVec.get(0)).getJSONObject("extractInfo");

        // case
        JSONObject caze = extractInfo.getJSONObject("case");
        if (caze != null) {
            result.put("case", caze.getString("mean"));
        }

        // suspect
        JSONArray suspects = extractInfo.getJSONArray("suspect");
        if (!suspects.isEmpty()) {
            JSONArray suspectsArray = new JSONArray();
            result.put("suspect", suspectsArray);

            for (Object suspect : suspects) {
                JSONObject suspectFields = new JSONObject();
                suspectsArray.add(suspectFields);

                JSONObject label = ((JSONObject) suspect).getJSONObject("label");
                for (Map.Entry<String, Object> entry : label.entrySet()) {
                    JSONArray fieldValueArray = (JSONArray) entry.getValue();
                    ArrayList<Object> values = Lists.newArrayList();
                    for (Object fieldValue : fieldValueArray) {
                        values.add(((JSONObject) fieldValue).getString("mean"));
                    }

                    suspectFields.put(entry.getKey(), values);
                }
            }
        }

        return result.toJSONString();
    }

    private String extractWordText(MultipartFile file) {
        try (InputStream is = file.getInputStream()) {
            return FileUtils.extractWordText(is);
        }
        catch (Exception e) {
            logger.warn("提取word文本内容异常", e);
        }
        return null;
    }

}
